﻿using HtmlAgilityPack;
using Microsoft.Extensions.Configuration;
using System;
using System.Net;
using System.Text;

namespace 小说爬虫 {
    internal class Program {
        static IConfigurationRoot _Config = new ConfigurationBuilder()
            .AddInMemoryCollection() //缓存
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .Build();
        static string _WebRoot;

        static async Task Main(string[] args) {
            Uri url = new Uri(_Config["WebUrl"]);
            _WebRoot = url.Host;
            var chapterList = await FetchChapterListAsync(_Config["WebUrl"]);

            await FetchContentAsync(chapterList);

            Console.WriteLine($"保存完毕！！！");
            Console.ReadLine();
        }

        static async Task<string> FetchHtmlContentAsync(string url) {
            var client = new HttpClient();
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var response = await client.SendAsync(request);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync();
            //替换方案使用Puppeteer Sharp，Node.js 的 Puppeteer API 的 .NET 版本实现。
        }

        //获取章节目录
        static async Task<List<(string Url, string Title)>> FetchChapterListAsync(string url) {
            string htmlContent = await FetchHtmlContentAsync(url);

            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(htmlContent);

            // 假设章节目录是在class为"ml_list"的div元素中的li元素  
            var chapterNodes = doc.DocumentNode.SelectNodes("//ul[@class='chapters']/li");

            if (chapterNodes == null) {
                throw new InvalidOperationException("没有找到章节目录");
            }

            var chapterTasks = chapterNodes.Select(node => {
                // 这里假设每个li元素包含完整的章节信息，或者你可以进一步解析以获取更多数据  
                string chapterText = node.InnerText.Trim();
                // 如果需要提取链接或其他信息，可以这样做：  
                var chapterLink = node.SelectSingleNode("a").GetAttributeValue("href", null);
                return (chapterLink, chapterText);
            }).ToList();

            return chapterTasks.ToList();
        }

        //获取章节内容并保存
        static async Task FetchContentAsync(List<(string Url, string Title)> chapterList) {
            // 顺序处理每个章节，并将内容追加到同一个文件中              
            using (StreamWriter writer = new StreamWriter(_Config["SaveAddress"], append: false)) // append: false 表示如果文件已存在，则覆盖它  
            {
                foreach (var chapter in chapterList) {
                    await Save(writer, chapter, 1);
                }
            }
        }

        static int num = 1;
        static async Task Save(StreamWriter writer, (string Url, string Title) chapter, int errNum) {
            try {
                Console.WriteLine($"{DateTime.Now.ToShortTimeString()}开始-{chapter.Title}");
                // 获取章节内容  
                //string htmlContent = await FetchHtmlContentAsync($"http://{_WebRoot}{chapter.Url}?r={num++}");
                string htmlContent = await FetchHtmlContentAsync($"{chapter.Url}?r={num++}");

                // 解析HTML内容
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(htmlContent);

                // 查找ID为articlecontent的p节点  
                var pNode = doc.GetElementbyId("acontent");
                //var pNode = doc.DocumentNode.SelectSingleNode("//div[@class='content']/div[@class='content']");

                // 替换&nbsp;为空格  
                string innerHtml = pNode.InnerHtml.Replace("&nbsp;", " ");

                // 替换<br>为换行符  
                string innerText = HtmlEntity.DeEntitize(WebUtility.HtmlDecode(innerHtml))
                    .Replace("<br>\n", "<br>")
                    .Replace("<br>", Environment.NewLine)
                    .Replace("<br/>", Environment.NewLine)
                    .Replace("<br />", Environment.NewLine);
                innerText = innerText.Substring(innerText.IndexOf("(读万卷 www.duwanjuan.info)")).Replace("(读万卷 www.duwanjuan.info)", "");
                innerText = innerText.Substring(0, innerText.LastIndexOf("读万卷 www.duwanjuan.info")).Replace("读万卷 www.duwanjuan.info", "");
                // 写入到文件中，可以添加一些分隔符或标题来区分章节  
                writer.WriteLine($"{chapter.Title}");
                writer.WriteLine(innerText);
                writer.WriteLine(new string('-', 50)); // 添加一个分隔线 

                Console.WriteLine($"{DateTime.Now.ToShortTimeString()}结束-{chapter.Title}");
            }
            catch (Exception ex) {
                Console.WriteLine($"{DateTime.Now.ToShortTimeString()}异常-{chapter.Title}: {ex.Message}");
                errNum++;
                if (errNum > 3) {
                    Console.WriteLine($"{DateTime.Now.ToShortTimeString()}异常-{chapter.Title}:异常3次，重试输入1，继续输入2");
                    var key = Console.ReadLine();
                    if (key == "1") {
                        await Save(writer, chapter, 1);
                    }
                }
                else {
                    await Save(writer, chapter, errNum);
                }
            }
        }
    }
}